package com.hdax.gulimall.order.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hdax.common.to.MemberEntity;
import com.hdax.common.to.OrderTo;
import com.hdax.common.utils.R;
import com.hdax.gulimall.order.constant.OrderConstant;
import com.hdax.gulimall.order.entity.OrderItemEntity;
import com.hdax.gulimall.order.entity.PaymentInfoEntity;
import com.hdax.gulimall.order.enume.OrderStatusEnum;
import com.hdax.gulimall.order.feign.MemberFeignService;
import com.hdax.gulimall.order.feign.CartFeignService;
import com.hdax.gulimall.order.feign.ProductFeignService;
import com.hdax.gulimall.order.feign.WmsFeignService;
import com.hdax.gulimall.order.interceptor.LoginUserInterceptor;
import com.hdax.gulimall.order.service.OrderItemService;
import com.hdax.gulimall.order.service.PaymentInfoService;
import com.hdax.gulimall.order.to.OrderCreateTo;
import com.hdax.gulimall.order.vo.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hdax.common.utils.PageUtils;
import com.hdax.common.utils.Query;
import com.hdax.gulimall.order.dao.OrderDao;
import com.hdax.gulimall.order.entity.OrderEntity;
import com.hdax.gulimall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {


    private ThreadLocal<OrderSubmitVo> submitVoThreadLocal=new ThreadLocal<>();

    @Autowired
    private MemberFeignService memberFeignService;

    @Autowired
    private CartFeignService cartFeignService;


    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private WmsFeignService wmsFeignService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Autowired
    private PaymentInfoService paymentInfoService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }


    /**
     * 查询订单详情
     *
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {
        MemberEntity memberEntity = LoginUserInterceptor.local.get();
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id",memberEntity.getId()).orderByDesc("id")
        );
        List<OrderEntity> collect = page.getRecords().stream().map(item -> {
            List<OrderItemEntity> order_sn = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", item.getOrderSn()));
            item.setOrderItemEntityList(order_sn);
            return item;
        }).collect(Collectors.toList());
        page.setRecords(collect);
        return new PageUtils(page);
    }

    /**
     * 支付宝异步通知(内网穿透)
     * @param payAsyncVo
     * @return
     */
    @Override
    public String handlePayResult(PayAsyncVo payAsyncVo) {

        /**
         * 保存交易流水
         */
        PaymentInfoEntity paymentInfoEntity=new PaymentInfoEntity();
        //支付宝流水号
        paymentInfoEntity.setAlipayTradeNo(paymentInfoEntity.getAlipayTradeNo());
        paymentInfoEntity.setOrderSn(payAsyncVo.getOut_trade_no());
        paymentInfoEntity.setPaymentStatus(payAsyncVo.getTrade_status());
        paymentInfoEntity.setCallbackContent(payAsyncVo.getNotify_id());
        boolean save = paymentInfoService.save(paymentInfoEntity);

        /**
         * 修改订单的状态
         */
        if(payAsyncVo.getTrade_status().equals("TRADE_SUCCESS")||payAsyncVo.getTrade_status().equals("TRADE_FINISHED")){
            System.out.println("订单消费成功");
            String orderSn = paymentInfoEntity.getOrderSn();
            this.baseMapper.updateOrderPayStatus(orderSn,OrderStatusEnum.PAYED.getCode());
        }

        /**
         * 验签
         */

        return "success";
    }




    /**
     *
     * @return
     */
    @Override
    public OrderConfirmVo  confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo confirmVo=new OrderConfirmVo();
        MemberEntity memberEntity = LoginUserInterceptor.local.get();
        /**
         * 获取当前线程请求头信息(解决Feign异步调用丢失请求头问题)
         */
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        /**
         * 1、远程查询当前用户所有收货地址列表
         */
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //元辰调用获取用户所关联的地址
            List<MemberAddressVo> address = memberFeignService.getAddress(memberEntity.getId());
            confirmVo.setAddress(address);
        }, threadPoolExecutor);

        /**
         * 2、远程查询购物车所有选中的项
         */
        CompletableFuture<Void> voidCompletableFuture1 = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //远程调用购物车服务，从redis中获取选中的商品
            List<OrderItemVo> orderItemVos = cartFeignService.getcurrentUserCartItem();
            confirmVo.setItems(orderItemVos);
            //查询库存数(批量查询每一个商品的库存信息)(根据商品的id集合)
     /*       List<OrderItemVo> items = confirmVo.getItems();
            //获取购物车中所有sku的id
            List<Long> collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
            //远程调用是否有库存
            R<List<SkuHasStockVo>> skuHasStock = wmsFeignService.getSkuHasStock(collect);
            List<SkuHasStockVo> data = skuHasStock.getData();
            if(data!=null){
                Map<Long, Boolean> collect1 = data.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
                confirmVo.setStocks(collect1);
            }*/
        }, threadPoolExecutor);
        //总金额和优惠金额在get方法中自动计算
        // TODO 防重令牌(防止表单重复提交)
        String replace = UUID.randomUUID().toString().replace("-", "");
        System.out.println("防重令牌"+replace);
        //给页面
        confirmVo.setOrderToken(replace);
        //服务器
        stringRedisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX+memberEntity.getId(),replace,30, TimeUnit.MINUTES);
        CompletableFuture.allOf(voidCompletableFuture,voidCompletableFuture1).get();
        return confirmVo;
    }




    /**
     * 创建订单
     * @param orderSubmitVo
     * @return
     */
    @Override
    @Transactional
    public SubmitResponseVo submitOrder(OrderSubmitVo orderSubmitVo) throws JsonProcessingException {
        SubmitResponseVo submitResponseVo=new SubmitResponseVo();
        //把前端传过来的数据放入线程
        submitVoThreadLocal.set(orderSubmitVo);
        MemberEntity memberEntity = LoginUserInterceptor.local.get();
        String orderToken = orderSubmitVo.getOrderToken();
        /**
         * 1、令牌的验证
         * 通过lure脚本原子 验证令牌和删除令牌
         */
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long result = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberEntity.getId()), orderToken);
        if(result==0L){
            //令牌验证失败
            submitResponseVo.setCode(1);
            return submitResponseVo;
        }else{
            //令牌验证成功,进行下单
            /**
             * 2、订单的创建
             */
            OrderCreateTo order = createOrder();
            /**
             * 3.验价
             */
            //获取商品的价格加上运费
            BigDecimal payAmount = order.getOrder().getPayAmount();
            BigDecimal payPrice = orderSubmitVo.getPayPrice();
            if(Math.abs(payAmount.subtract(payPrice).doubleValue())<0.01){
                /**
                 * 4.验价成功 保存订单
                 */
                saveOrder(order);
                /**
                 * 5.锁定库存
                 */
                WareSkuLockVo wareSkuLockVo=new WareSkuLockVo();
                wareSkuLockVo.setOrderSn(order.getOrder().getOrderSn());
                List<OrderItemVo> collect = order.getOrderItems().stream().map(item -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    //要锁定的sku
                    orderItemVo.setSkuId(item.getSkuId());
                    //订单项的数量
                    orderItemVo.setCount(item.getSkuQuantity());
                    orderItemVo.setTitle(item.getSkuName());
                    return orderItemVo;
                }).collect(Collectors.toList());
                wareSkuLockVo.setLocks(collect);
                //调用远程服务锁定库存
                R r = wmsFeignService.orderLockStock(wareSkuLockVo);
                Integer code = (Integer) r.get("code");
                if(code==0){
                    //锁定成功
                    submitResponseVo.setCode(0);
                    submitResponseVo.setOrder(order.getOrder());
                    /**
                     * 订单创建成功向Rabbitmq发送消息
                     */
                    //交换机 队列的路由键 发送的消息
                    rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getOrder());
                    return submitResponseVo;
                }else{
                    //锁定失败
                    submitResponseVo.setCode(3);
                    return submitResponseVo;
                }
            }else{
                //验价失败
                submitResponseVo.setCode(2);
                return submitResponseVo;
            }
        }
    }

    /**
     * 关闭订单
     * @param orderEntity
     */
    @Override
    public void closeOrder(OrderEntity orderEntity) {
        //查询当前这个订单的最新状态,只对待付款状态的订单进行关单
        OrderEntity orderInfo = this.getOne(new QueryWrapper<OrderEntity>().
                eq("order_sn",orderEntity.getOrderSn()));
        //待付款状态
        if(orderInfo.getStatus()== OrderStatusEnum.CREATE_NEW.getCode()){
            //订单状态修改为取消
            OrderEntity orderEntity1=new OrderEntity();
            orderEntity1.setId(orderInfo.getId());
            orderEntity1.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(orderEntity1);
            OrderTo orderTo=new OrderTo();
            BeanUtils.copyProperties(orderEntity,orderTo);
           try {
               /**
                * 保证每个消息都一定发出去,每一个消息都可以做好日志记录(给数据库保存每一个消息的详细信息)
                * 定期扫描数据库将失败的消息从新发送
                */
               rabbitTemplate.convertAndSend("order-event-exchange","order.release.other",orderTo);
           }catch (Exception e){

               //将没发送成功的消息进行重试发送
           }
        }
    }

    /**
     * 订单支付信息
     * @param orderSn
     * @return
     */
    @Override
    public PayVo getOrderPay(String orderSn) {
        PayVo pay=new PayVo();
        OrderEntity order_sn = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        //小数点后面精确到两位(向上取整)
        BigDecimal bigDecimal = order_sn.getPayAmount().setScale(2,BigDecimal.ROUND_UP);
        pay.setTotal_amount(bigDecimal.toString());
        pay.setOut_trade_no(orderSn);
        OrderItemEntity order_sn1 = orderItemService.getOne(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
        pay.setSubject(order_sn1.getSkuName());
        pay.setBody(order_sn1.getSkuAttrsVals());
        return pay;
    }



    /**
     * 保存订单数据
     * @param order
     */
    private void saveOrder(OrderCreateTo order) {
        //保存订单
        OrderEntity order1 = order.getOrder();
        this.save(order1);
        //保存订单对应的订单项
        List<OrderItemEntity> orderItems = order.getOrderItems();
        boolean b = orderItemService.saveBatch(orderItems);
    }


    /**
     * 创建订单
     * @return
     * @throws JsonProcessingException
     */
    private OrderCreateTo createOrder() throws JsonProcessingException {
        OrderCreateTo orCreateTo=new OrderCreateTo();
        //1.订单的信息order
        OrderEntity order = getOrder();
        orCreateTo.setOrder(order);
        //2.订单项的信息orderItem
        List<OrderItemEntity> orderItems = bulidOrderItems(order.getOrderSn());
        orCreateTo.setOrderItems(orderItems);
        //3.验证价格
        computePrice(order,orderItems);
        return orCreateTo;
    }


    /**
     * 计算价格相关
     * @param order
     * @param list
     */
    private void computePrice(OrderEntity order, List<OrderItemEntity> list) {
        BigDecimal total=new BigDecimal("0.0");
        BigDecimal coupon=new BigDecimal("0.0");
        BigDecimal integration=new BigDecimal("0.0");
        BigDecimal promotion=new BigDecimal("0.0");
        //积分成长值
        Integer gift=0;
        Integer growth=0;
        //计算订单的商品总额
        for (OrderItemEntity orderItemEntity : list) {
            //订单的总金额
            coupon=coupon.add(orderItemEntity.getCouponAmount());
            integration=integration.add(orderItemEntity.getIntegrationAmount());
            promotion=promotion.add(orderItemEntity.getIntegrationAmount());
            //计算总价格
            total=total.add(orderItemEntity.getRealAmount());
            gift+=orderItemEntity.getGiftGrowth();
            gift+=orderItemEntity.getGiftIntegration();
        }
        //订单总额
        order.setTotalAmount(total);
        //应付总额(订单总额加运费)
        order.setPayAmount(total.add(order.getFreightAmount()));
        order.setPromotionAmount(promotion);
        order.setCouponAmount(coupon);
        //设置删除状态
        order.setDeleteStatus(0);
    }


    /**
     * 订单信息
     */
    private OrderEntity getOrder() throws JsonProcessingException {
        MemberEntity memberEntity = LoginUserInterceptor.local.get();
        OrderSubmitVo orderSubmitVo = submitVoThreadLocal.get();
        OrderEntity orderEntity=new OrderEntity();
        orderEntity.setMemberId(memberEntity.getId());
        orderEntity.setCreateTime(new Date());
        orderEntity.setMemberUsername(memberEntity.getUsername());
        //mybatisplus订单号
        String timeId = IdWorker.getTimeId();
        orderEntity.setOrderSn(timeId);
        //收货地址信息
        R fare = wmsFeignService.getFare(orderSubmitVo.getAddrId());
        Object data = fare.get("data");
        FareVo fareVo = objectMapper.readValue(objectMapper.writeValueAsString(data), FareVo.class);
        //运费
        orderEntity.setFreightAmount(fareVo.getFare());
        //收货信息
        orderEntity.setReceiverProvince(fareVo.getAddress().getProvince());//省份
        orderEntity.setReceiverCity(fareVo.getAddress().getCity());
        orderEntity.setReceiverRegion(fareVo.getAddress().getRegion());//区
        orderEntity.setReceiverDetailAddress(fareVo.getAddress().getDetailAddress());
        orderEntity.setReceiverName(fareVo.getAddress().getName());
        orderEntity.setReceiverPhone(fareVo.getAddress().getPhone());
        //邮编
        orderEntity.setReceiverPostCode(fareVo.getAddress().getPostCode());
        //订单的状态信息(待付款状态)
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        return orderEntity;
    }


    /**
     * 获取到所有的订单项
     */
    private List<OrderItemEntity> bulidOrderItems(String OrderSn) {
        //远程调用购物车选中的商品
        List<OrderItemVo> orderItemVos = cartFeignService.getcurrentUserCartItem();
        if(orderItemVos!=null&&orderItemVos.size()>0){
            List<OrderItemEntity> collect = orderItemVos.stream().map(cartItem -> {
                OrderItemEntity orderItemEntity= null;
                try {
                    orderItemEntity = getOrderItem(cartItem);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
                //订单号
                orderItemEntity.setOrderSn(OrderSn);
                return orderItemEntity;
            }).collect(Collectors.toList());
            return collect;
        }
        return null;
    }

    /**
     * 构建每一个订单项(购物车选中的商品)
     * @param cartItem
     * @return
     */
    private OrderItemEntity getOrderItem(OrderItemVo cartItem) throws JsonProcessingException {
        OrderItemEntity orderItemEntity=new OrderItemEntity();
        /**
         * 1.sku的信息
         */
        orderItemEntity.setSkuId(cartItem.getSkuId());
        orderItemEntity.setSkuName(cartItem.getTitle());
        orderItemEntity.setSkuPic(cartItem.getImges());
        orderItemEntity.setSkuPrice(cartItem.getPrice());
        orderItemEntity.setRealAmount(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())));
        //集合的转换(将list转换为string) StringUtils.collectionToDelimitedString
        String skuAttr = StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(), ";");
        orderItemEntity.setSkuAttrsVals(skuAttr);
        orderItemEntity.setSkuQuantity(cartItem.getCount());
        /**
         * 2.spu的信息
         */
        R spuInfoBySku = productFeignService.getSpuInfoBySku(cartItem.getSkuId());
        Object data = spuInfoBySku.get("data");
        SpuInfoVo spuInfoVo = objectMapper.readValue(objectMapper.writeValueAsString(data), SpuInfoVo.class);
        orderItemEntity.setSpuId(spuInfoVo.getId());
        orderItemEntity.setSpuBrand(spuInfoVo.getBrandId().toString());
        orderItemEntity.setSpuName(spuInfoVo.getSpuName());
        orderItemEntity.setCategoryId(spuInfoVo.getCatalogId());


        /**
         * 3.商品的积分信息和成长值
         */
        orderItemEntity.setGiftGrowth(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())).intValue());
        orderItemEntity.setGiftIntegration(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())).intValue());


        /**
         * 4.订单项的优惠信息
         */
        orderItemEntity.setPromotionAmount(new BigDecimal("0"));
        orderItemEntity.setCouponAmount(new BigDecimal("0"));
        orderItemEntity.setIntegrationAmount(new BigDecimal("0"));

        /**
         * 5.当前订单的实际金额总金额-各种优惠
         * skuPrice*count
         */
        BigDecimal multiply = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity()));
        BigDecimal subtract = multiply.subtract(orderItemEntity.getPromotionAmount()).subtract(orderItemEntity.getIntegrationAmount());
        orderItemEntity.setRealAmount(subtract);
        return orderItemEntity;
    }


}